/********************************************
 * Class QLyric
 * Qt Lyric 歌词解析类 类声明及宏、结构定义
 *
 * QLyric.h
 * By sunnysab (sunnysab@yeah.net)
 * 不得用于收费软件，并在软件中标明使用本库及作者
 *
*********************************************/

#ifndef LYRIC_H
#define LYRIC_H

#include <QString>
#include <QList>


// 预定义的函数返回值
#define     LRC_SUCCESS    0x00  // 操作成功完成
#define     LRC_FILE_ERR   0x02  // 文件错误
#define     LRC_FORMAT_ERR 0x03  // 参数格式错误
#define     LRC_NO_DATA    0x04  // 无数据
#define     LRC_PARA_ERR   0x05  // 参数错误


typedef int  LRC_RESULT;  // 返回值类型
typedef int  LyricIndex;  // 歌词行索引类型
typedef int  LyricTime;   // 歌词时间类型


// 调试开关
#define   LRC_DEBUG


// 结构 _LyricLine
// 用于存储歌词时间和内容
typedef struct  _LyricLine
{
    LyricTime     nTime;        // 歌词时间
    QString       strLineData;  // 歌词内容

}LYRICLINE;


/********************************************
// 以下各行根据 维基百科 资料改来的
typedef struct  _LyricInfo
{
    QString  al;   // 本歌所在的唱片集
    QString  ar;   // 歌词作者
    QString  by;   // 此LRC文件的创建者
    QString  re;   // 创建此LRC文件的播放器或编辑器
    QString  ti;   // 歌词(歌曲)的标题
    QString  ve;   // 程序的版本

}LYRICINFO;
********************************************/

class  QLyric
{
/*****************************
 * QLyric 私有数据
 *****************************/
private:

    // 最后一次打开的歌词文件路径
    QString            m_LrcFileName;
    // 存储歌词行列表
    QList<LYRICLINE>   m_LineList;


/*****************************
 * QLyric 公共接口
 *****************************/
public:

    /*
     * 名    称: QLyric
     * 属    性: 构造函数
     */
    QLyric();

    QLyric operator +(
            const QLyric  &lrc2
            );

    QLyric operator +=(
            const QLyric  &lrc2
            );

    QLyric operator +=(
            const LYRICLINE  &stLyricLine
            );

    /*
     * 名    称: LoadFromFile
     * 功    能: 从文件加载歌词
     * 返    回: LRC_RESULT 类型
     *          LRC_FILE_ERR 表示无法打开文件或者文件大小为空
     *          返回 LRC_SUCCESS 表示无错误发生
     */
    LRC_RESULT  LoadFromFile(
                            // 要加载的文件名, 不要求 .lrc 结尾
                            const QString  &strFileName
                            );

    /*
     * 名    称: SaveToFile
     * 功    能: 保存内存中存储的歌词到文件
     * 返    回: LRC_RESULT 类型
     *          LRC_FILE_ERR 表示无法保存文件
     *          返回 LRC_SUCCESS 表示无错误发生
     */
    LRC_RESULT  SaveToFile(
            // 要保存的文件名
            const QString  &strFileName,
            // 保存为 ANSI 编码格式，false 表示使用 UTF-8
            bool IsAscii = true
            );


    /*
     * 名    称: GetLineCount
     * 功    能: 获得内存中歌词总数(/行)
     * 返    回: unsigned int 类型
     *          歌词行的总数
    */
    unsigned int  GetLineCount(void);

    /*
     * 名    称: RemoveAll
     * 功    能: 删除所有歌词
    */
    void  RemoveAll(void);


    /*
     * 名    称: AppendLine
     * 功    能: 添加一行歌词
     */
    void AppendLine(
            const LYRICLINE  &stLyricLine  // 要添加的行结构
            );

    /*
     * 名    称: AppendLine
     * 功    能: 添加一行歌词
     */
    void AppendLine(
            LyricTime  nTime,        // 时间
            const QString  &strNewLine      // 歌词内容
            );

    /*
     * 名    称: InsertLine
     * 功    能: 在 nLine 处插入一个新行
     */
    void InsertLine(
            LyricIndex  nLine,   // 行索引
            const LYRICLINE  &stLyricLine   // 要插入的新行
            );

    /*
     * 名    称: InsertLine
     * 功    能: 在 nLine 处插入一个新行
     */
    void InsertLine(LyricIndex  nLine,   // 行索引
            LyricTime  nTime,    // 歌词时间
            const QString &strNewLine  // 歌词内容
            );

    /*
     * 名    称: DeleteLine
     * 功    能: 删除行
     * 返    回: 如果找不到索引为 nLine 的数据，返回 LRC_PARA_ERR
     *          调用者可以先确认行索引是否正确
     */
    LRC_RESULT  DeleteLine(
            LyricIndex  nLine  // 要删除行的索引
            );

    /*
     * 名    称: AlterLine
     * 功    能: 修改行
     * 返    回: 如果找不到索引为 nLine 的数据，返回 LRC_PARA_ERR
     *          调用者可以先确认行索引是否正确
     */
    LRC_RESULT  AlterLine(
            LyricIndex  nLine,         // 要修改行的索引
            LYRICLINE  stLyricLineNew  // 新的行数据
            );

    /*
     * 名    称: AlterLine
     * 功    能: 修改行
     * 属    性: public
     * 返    回: 见 (1)
     */
    LRC_RESULT  AlterLine(LyricIndex  nLine,     // 要修改行的索引
            LyricTime  nTimeNew,   // 新的时间
            const QString &strNewData    // 新的歌词内容
            );

    /*
     * 名    称: GetLyricLine
     * 功    能: 获得索引为 nLine 的行的内容
     * 参    数: LyricIndex    nLine           要获取的行的索引
     *          LYRICLINE     &LyricLine      一个 LYRICLINE 的引用
     * 返    回: 如果找不到索引为 nLine 的数据，返回 LRC_PARA_ERR
     *          调用者可以先确认行索引是否正确
     */
    LRC_RESULT  GetLyricLine(
            LyricIndex  nLine,      // 要获取的行的索引
            LYRICLINE  &LyricLine   // 一个 LYRICLINE 的引用
            );

    /*
     * 名    称: Sort
     * 功    能: 排序歌词
     */
    void Sort(void);

    /*
     * 名    称: SetTimeOffset
     * 功    能: 为全部歌词设置时间偏移
     * 说    明: nTimeOffsetMS 正为后移，负为前移，函数内部会对移动范围进行检查
     */
    void SetTimeOffset(
            const int  nTimeOffset10MS  // 10 毫秒为单位的时间偏移量
            );


    /*
     * 名    称: GetTimeFromString
     * 功    能: 将时间标签转换为以10毫秒为单位的数值
     * 返    回: LyricTime 类型，转换后以10毫秒为单位
     */
    static LyricTime GetTimeFromString(const QString &strTime    // 要转换的时间标签
            );

    /*
     * 名    称: GetStringFromTime
     * 功    能: 将以 百分之一秒 为单位的时间数据转换成 [MM:SS:XX] 格式
     *          或 [MM:SS] 的字符串，详见注释
     * 返    回: 转换后的字符串
     * 说    明: 见 GetStringFromTime (2)
     */
    static QString GetStringFromTime(
            LyricTime  nTime,      // 以 百分之一秒 为单位的时间
            QString &strTime,      // 转换后的字符串数据
            bool bIsSimple = false // 表示是否以简单形式转换
            );

    /*
     * 名    称: GetStringFromTime
     * 功    能: 将以 百分之一秒 为单位的时间数据转换成 [MM:SS:XX] 格式
     *          或 [MM:SS] 的字符串，详见注释
     * 返    回: 转换后的字符串
     * 说    明: 如果 bIsSimple 为 true， 那么当 nXX == 0 时，字符串将转换成
     *          [MM:SS] 形式，不过为了使 LRC 文件更加清晰，建议选false
     */
    static QString GetStringFromTime(
            LyricTime  nMM,      // 以 分 为单位的时间
            LyricTime  nSS,      // 以 秒 为单位的时间
            LyricTime  nXX,      // 以 百分之一秒 为单位的时间
            QString  &strTime,   // 转换后的字符串数据
            bool bIsSimple = false  // 表示是否以简单形式转换
            );

    /*
     * 名    称: GetLyricFromString
     * 功    能: 从行中提取出歌词内容
     * 返    回: LRC_NO_DATA 表示找不到时间标签，成功返回 LRC_SUCCESS
     */
    static LRC_RESULT  GetLyricFromString(const QString &strLine,    // 要提取的lrc行
            QString  &strLyric   // 存放提取出的歌词
            );

#ifdef  LRC_DEBUG
    /*
     * 名    称: PrintAll
     * 功    能: 输出 m_LineList 内所有行
     * 说    明: 此函数仅 LRC_DEBUG 声明时可用，供调试使用
     */

    void  PrintAll(void);
#endif



// private:

    /*
     * 名    称: CheckTimeLable
     * 功    能: 检查时间标签是否准确
     * 返    回: bool 类型 表示该时间标签是否合法
     * 说    明: 代码有待完善
     */
    static bool  CheckTimeLable(
            const QString  &strTimeLabel  // 要检查的时间标签
            );

    /*
     * 名    称: ResolveLine
     * 功    能: 解析歌词行，并将其添加至列表
     * 返    回: 类型 LRC_RESULT
     * 说    明: 返回 LRC_FORMAT_ERR 表示 strLine 的时间标签格式有错
     *          LRC_NO_DATA 请检查是否含有时间标签， 成功返回 LRC_SUCCESS
     *          如果某一个时间标签无法解析或错误，转换继续执行
     */
    LRC_RESULT  ResolveLine(const QString &strLine   // 一行歌词数据
            );


    /*
     * 名    称: ResolveLines
     * 功    能: 解析歌词文件
     * 说    明: 函数会过滤每一行的换行符，并得到歌词相关信息
     */
    void ResolveLines(
            QStringList  strLines  // lrc文件全部歌词行
            );

    /*
     * 名    称: CompareTime
     * 功    能: 返回 stLine1 的时间是否在 stLine2 之前
     * 说    明: 本函数供排序函数回调，见 QLyric::Sort()
     */
    static bool  CompareTime(
            const LYRICLINE  &stLine1,   // 要比较的行1
            const LYRICLINE  &stLine2    // 要比较的行2
            );

};

#endif // LYRIC_H
